package main

type operation int 

const (
    sub operation = itoa
    subOnce 
    pub
    typPub
    unsub
    unsubAll
    closeTopic
    shutdown
)

type PubSub struct {
    cmdChan chan cmd
    capactity int
}

type cmd struct {
    op operation
    topics []string
    ch chan interface{}
    msg interface{}
} 

func New(capactity int)* PubSub {
    ps := &PubSub{make(chan cmd), capacity}
    go ps.start()
    return ps
}

func (ps *PubSub)Sub(topics ...string) chan interface{} {
    return ps.sub(sub, topics...)
}

func (ps *PubSub)SubOnce(topics ...string) chan interface{} {
    return ps.sub(subOnce, topics...)
}

func (ps *PubSub) sub(op operation, topics ...string) chan interface{} {
    ch := make(chan interface{}, ps.capacity)
    ps.cmdChan <- cmd{op: op, topics:topics, ch:ch)
    return ch
}

func (ps *PubSub) AddSub(ch chan interface{}, topics ...string) {
    ps.cmdChan <- cmd{op:sub, topics:topics, ch:ch}
}

func(ps *PubSub) Pub(msg interface{}, topics ..string) {
    ps.cmdChan <- cmd{op:pub, topics:topics, msg:msg}
}

func(ps *PubSub) TryPub(msg interface{}, topics ...string) {
    ps.cmdChan <- cmd{op:tryPub, topics:topics, msg:msg}
}

func (ps *PubSub) UnSub(ch chan interface{}, topics ...string) {
    if len(topics) == 0 {
        ps.cmdChan <- cmd{op:unsubAll, ch:ch} 
        return 
    }
    ps.cmdChan <- cmd{op:unsub, topics:topics, ch:ch}
}

func (ps *PubSub) Close(topics ...string) {
    ps.cmdChan <- cmd{op:closeTopic, topics:topics}
}

func (ps *PubSub) ShutDown() {
    ps.cmdChan <- cmd{op:shutdown}
}


func (ps *PubSub) start() {
    reg := registry{
        topics : make(map[string]map[chan interface{}]bool),
        revTopics: make(map[chan interface{}]map[string]bool),
    }
loop:
    for cmd := range ps.cmdChan {
        if cmd.topics == nil {
            switch cmd.op{
            case unsubAll:
                reg.removeChannel(cmd.ch)
            case shutdown:
                break  loop
            continue loop
        } 
        for _, topic := range cmd.topics {
            switch cmd.op {
            }
        }

    }
}








